package com.mbigger.admin.service.impl;

import java.util.Date;
import java.util.List;

import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.google.common.base.Preconditions;
import com.mbigger.admin.common.RequestHolder;
import com.mbigger.admin.dao.DeptMapper;
import com.mbigger.admin.dao.UserMapper;
import com.mbigger.admin.entity.Department;
import com.mbigger.admin.exception.ParamException;
import com.mbigger.admin.param.DeptParam;
import com.mbigger.admin.service.DeptService;
import com.mbigger.admin.util.BeanValidator;
import com.mbigger.admin.util.IpUtil;
import com.mbigger.admin.util.LevelUtil;

@Service
public class DeptServiceImpl implements DeptService{
	
	@Autowired
	private DeptMapper deptMapper;
	@Autowired
	private UserMapper userMapper;

	public Integer save(DeptParam param) {
		BeanValidator.check(param);
		if (checkExist(param.getParentId(), param.getName(), param.getId())) {
			throw new ParamException("同一层级下存在相同名称的部门");
		}
		Department dept = Department.builder().name(param.getName()).parentId(param.getParentId()).seq(param.getSeq())
				.remark(param.getRemark()).build();

		dept.setLevel(LevelUtil.calculateLevel(getLevel(param.getParentId()), param.getParentId()));
		dept.setOperator(RequestHolder.getCurrentUser().getUsername());
		dept.setOperateIp(IpUtil.getRemoteIp(RequestHolder.getCurrentRequest()));
		dept.setOperateTime(new Date());
		return deptMapper.insert(dept);
	}

	public void update(DeptParam param) {
		BeanValidator.check(param);
		if (checkExist(param.getParentId(), param.getName(), param.getId())) {
			throw new ParamException("同一层级下存在相同名称的部门");
		}
		Department before = deptMapper.selectById(param.getId());
		Preconditions.checkNotNull(before, "待更新的部门不存在");
		if (checkExist(param.getParentId(), param.getName(), param.getId())) {
			throw new ParamException("同一层级下存在相同名称的部门");
		}

		Department after = Department.builder().id(param.getId()).name(param.getName()).parentId(param.getParentId())
				.seq(param.getSeq()).remark(param.getRemark()).build();
		after.setLevel(LevelUtil.calculateLevel(getLevel(param.getParentId()), param.getParentId()));
		after.setOperator(RequestHolder.getCurrentUser().getUsername());
		after.setOperateIp(IpUtil.getRemoteIp(RequestHolder.getCurrentRequest()));
		after.setOperateTime(new Date());

		updateWithChild(before, after);
	}

	@Transactional // 如果要保证事务生效，需要调整这个方法，一个可行的方法是重新创建一个service类，然后把这个方法转移过去
	public void updateWithChild(Department before, Department after) {
		String newLevelPrefix = after.getLevel();
		String oldLevelPrefix = before.getLevel();
		if (!after.getLevel().equals(before.getLevel())) {
			String curLevel = before.getLevel() + "." + before.getId();
			List<Department> deptList = deptMapper.getChildDeptListByLevel(curLevel + "%");
			if (CollectionUtils.isNotEmpty(deptList)) {
				for (Department dept : deptList) {
					String level = dept.getLevel();
					if (level.equals(curLevel) || level.indexOf(curLevel + ".") == 0) {
						// getChildAclModuleListByLevel可能会取出多余的内容，因此需要加个判断
						// 比如0.1* 可能取出0.1、0.1.3、0.11、0.11.3，而期望取出 0.1、0.1.3， 因此呢需要判断等于0.1或者以0.1.为前缀才满足条件
						level = newLevelPrefix + level.substring(oldLevelPrefix.length());
						dept.setLevel(level);
					}
				}
				deptMapper.batchUpdateLevel(deptList);
			}
		}
		deptMapper.updateById(after);
	}

	private boolean checkExist(Integer parentId, String deptName, Integer deptId) {
		return deptMapper.countByNameAndParentId(parentId, deptName, deptId) > 0;
	}

	private String getLevel(Integer deptId) {
		Department dept = deptMapper.selectById(deptId);
		if (dept == null) {
			return null;
		}
		return dept.getLevel();
	}

	public void delete(int deptId) {
		Department dept = deptMapper.selectById(deptId);
		Preconditions.checkNotNull(dept, "待删除的部门不存在，无法删除");
		if (deptMapper.countByParentId(dept.getId()) > 0) {
			throw new ParamException("当前部门下面有子部门，无法删除");
		}
		if (userMapper.countByDeptId(dept.getId()) > 0) {
			throw new ParamException("当前部门下面有用户，无法删除");
		}
		deptMapper.deleteById(deptId);
	}
}
